package com.sise.cn.dao.config;

import com.github.pagehelper.PageHelper;
import com.sise.cn.dao.pagehelper.PageHelperWrapper;
import com.sise.cn.dao.pagehelper.property.Dialect;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.Data;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

/**
 * @author CCJ
 */
@Data
@Configuration
public class BaseMyBatisConfig {

    @Autowired
    private Environment env;
    
    private static final String BASE_MAPPER_LOCATION = "classpath*:mappings/*Mapper.xml";

    /**
     * alias所在包，用;隔开
     *
     * @return alias location
     */
    private String getAlias() {
        return env.getProperty("datasource.alias", "com.sise.cn.*.po");
    }

    /**
     * mapper文件所在文件夹
     *
     * @return mapper location
     */
    private String[] getMapperLocation() {
        return env.getProperty("datasource.mapper",String[].class,new String[]{"classpath*:mappings/*Mapper.xml"});
    }

    /**
     * 数据源
     *
     * @return 数据源
     */
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(env.getProperty("datasource.url", "jdbc:mysql://localhost:3306/mysql?useUnicode=yes&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true"));
        config.setUsername(env.getProperty("datasource.username", "root"));
        config.setPassword(env.getProperty("datasource.password"));
        config.setAutoCommit(Boolean.valueOf(env.getProperty("datasource.auto-commit", "true")));
        config.setMaximumPoolSize(Integer.valueOf(env.getProperty("datasource.maximum-pool-size", "50")));
        return new HikariDataSource(config);
    }

    /**
     * SqlSession工厂
     *
     * @param dataSource 数据源
     * @return SqlSession工厂
     * @throws Exception 防止必要信息缺失
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sfb = new SqlSessionFactoryBean();
        sfb.setDataSource(dataSource);
        sfb.setTypeAliasesPackage(getAlias());
        PathMatchingResourcePatternResolver path = new PathMatchingResourcePatternResolver();
        Resource[] resources = {};
        for (String str : getMapperLocation()) {
            Resource[] re = path.getResources(str);
            if (re.length <= 0) {
                continue;
            }
            resources = addResource(resources, re);
        }
        Resource[] re = path.getResources(BASE_MAPPER_LOCATION);
        resources = addResource(resources, re);
        sfb.setMapperLocations(resources);
        sfb.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
        // 插件：
        // 1. pageHelper插件
        PageHelper pageHelper = PageHelperWrapper.newInstance().setDialect(Dialect.MYSQL)
                .setRowBoundsWithCount(true).setPageSizeZero(true).get();

        // 2. 后续可能有sharding插件
        sfb.setPlugins(new Interceptor[]{pageHelper});
        return sfb.getObject();
    }
    
    private Resource[] addResource(Resource[] resources, Resource[] re){
        int len = resources.length + re.length;
        Resource[] tmp = new Resource[len];
        System.arraycopy(resources, 0, tmp, 0, resources.length);
        System.arraycopy(re, 0, tmp, resources.length, re.length);
        return tmp;
    }

    /**
     * 事务管理器
     *
     * @param dataSource 需要被管理的数据源
     * @return 事务管理器
     */
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }

    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        //设置简单执行器，防止事务处理时无法返回自增主键
        sqlSessionFactory.getConfiguration().setDefaultExecutorType(ExecutorType.SIMPLE);
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}
